package GameControl;

import java.awt.Color;
import java.io.Serializable;
import net.percederberg.tetris.Configuration;

/**
 * Contains status of the game.
 * 
 * @author Dimon
 */
public class GameState implements Serializable {

    public Color[][] matrix;
    private Color color;
    private int rnd = 0;
    private int xPos = 0;
    private int yPos = 0;
    private int orientation = 0;
    private int maxOrientation = 0;
    private int shape = 0;
    private int[] shapeX = new int[4];
    private int[] shapeY = new int[4];

    /**
     * Creates new game state. Control package relies on
     * <code>GameState()</code> constructor during initialization.
     */
    public GameState() {
        matrix = new Color[GameControl.game.board.getBoardHeight()]
                          [GameControl.game.board.getBoardWidth()];
        newFigure();
        Draw();
    }

    private double myRandom() {
        rnd += 23;
        rnd %= 28;
        //System.err.println(((double) rnd) / 28.0);
        return ((double) rnd) / 28.0;
    }

    public void newFigure() {
        shape = ((int) (myRandom() * 7)) + 1;

        switch (shape) {
            case 1:
                maxOrientation = 1;
                color = Configuration.getColor("figure.square", "#ffd8b1");
                shapeX[0] = -1;
                shapeY[0] = 0;
                shapeX[1] = 0;
                shapeY[1] = 0;
                shapeX[2] = -1;
                shapeY[2] = 1;
                shapeX[3] = 0;
                shapeY[3] = 1;
                break;
            case 2:
                maxOrientation = 2;
                color = Configuration.getColor("figure.line", "#ffb4b4");
                shapeX[0] = -2;
                shapeY[0] = 0;
                shapeX[1] = -1;
                shapeY[1] = 0;
                shapeX[2] = 0;
                shapeY[2] = 0;
                shapeX[3] = 1;
                shapeY[3] = 0;
                break;
            case 3:
                maxOrientation = 2;
                color = Configuration.getColor("figure.s", "#a3d5ee");
                shapeX[0] = 0;
                shapeY[0] = 0;
                shapeX[1] = 1;
                shapeY[1] = 0;
                shapeX[2] = -1;
                shapeY[2] = 1;
                shapeX[3] = 0;
                shapeY[3] = 1;
                break;
            case 4:
                maxOrientation = 2;
                color = Configuration.getColor("figure.z", "#f4adff");
                shapeX[0] = -1;
                shapeY[0] = 0;
                shapeX[1] = 0;
                shapeY[1] = 0;
                shapeX[2] = 0;
                shapeY[2] = 1;
                shapeX[3] = 1;
                shapeY[3] = 1;
                break;
            case 5:
                maxOrientation = 4;
                color = Configuration.getColor("figure.right", "#c0b6fa");
                shapeX[0] = -1;
                shapeY[0] = 0;
                shapeX[1] = 0;
                shapeY[1] = 0;
                shapeX[2] = 1;
                shapeY[2] = 0;
                shapeX[3] = 1;
                shapeY[3] = 1;
                break;
            case 6:
                maxOrientation = 4;
                color = Configuration.getColor("figure.left", "#f5f4a7");
                shapeX[0] = -1;
                shapeY[0] = 0;
                shapeX[1] = 0;
                shapeY[1] = 0;
                shapeX[2] = 1;
                shapeY[2] = 0;
                shapeX[3] = -1;
                shapeY[3] = 1;
                break;
            case 7:
                maxOrientation = 4;
                color = Configuration.getColor("figure.triangle", "#a4d9b6");
                shapeX[0] = -1;
                shapeY[0] = 0;
                shapeX[1] = 0;
                shapeY[1] = 0;
                shapeX[2] = 1;
                shapeY[2] = 0;
                shapeX[3] = 0;
                shapeY[3] = 1;
                break;
            default:
        }

        orientation = ((int) (myRandom() * 4)) % maxOrientation;
        xPos = GameControl.game.board.getBoardWidth() / 2;
        yPos = 0;
        for(int i = 0; i < 4; i++) {
            while (getRelativeY(i) + yPos >= 0) {
                yPos--;
            }
        }
    }

    private int getRelativeX(int square) {
        switch (orientation % maxOrientation) {
        case 0 :
            return shapeX[square];
        case 1 :
            return -shapeY[square];
        case 2 :
            return -shapeX[square];
        case 3 :
            return shapeY[square];
        default:
            return 0; // Should never occur
        }
    }
    
    private int getRelativeY(int square) {
        switch (orientation % maxOrientation) {
        case 0 :
            return shapeY[square];
        case 1 :
            return shapeX[square];
        case 2 :
            return -shapeY[square];
        case 3 :
            return -shapeX[square];
        default:
            return 0; // Should never occur
        }
    }
    
    private void Remove() {
        int x, y;
        for(int i = 0; i < 4; i++) {
            x = xPos + getRelativeX(i);
            y = yPos + getRelativeY(i);
            if (x < 0 || x >= GameControl.game.board.getBoardWidth() ||
                y < 0 || y >= GameControl.game.board.getBoardHeight()) {
                //nop
            } else {
                matrix[y][x] = null;
            }
        }
    }
    
    private boolean Check() {
        int x, y;
        for(int i = 0; i < 4; i++) {
            x = xPos + getRelativeX(i);
            y = yPos + getRelativeY(i);
            if (x < 0 || x >= GameControl.game.board.getBoardWidth() ||
                y >= GameControl.game.board.getBoardHeight()) {
                return false;
            }
            if (y < 0) {
                continue;
            }
            if (matrix[y][x] != null) {
                return false;
            }
        }
        return true;
    }
    
    private void Draw() {
        int x, y;
        for(int i = 0; i < 4; i++) {
            x = xPos + getRelativeX(i);
            y = yPos + getRelativeY(i);
            if (x < 0 || x >= GameControl.game.board.getBoardWidth() ||
                y < 0 || y >= GameControl.game.board.getBoardHeight()) {
                //nop
            } else {
                matrix[y][x] = color;
            }
        }
        GameControl.game.board.matrix = matrix.clone();
        GameControl.game.board.update();
    }
    
    public void moveDown() {
        rnd += 7;
        Remove();
        yPos = yPos + 1;
        if (!Check()) {
            yPos = yPos - 1;
            Draw();
            GameControl.game.board.removeFullLines();
            matrix = GameControl.game.board.matrix.clone();
            newFigure();
            Draw();
        } else {
            Draw();
        }
    }

    public void moveLeft() {
        rnd += 13;
        Remove();
        xPos = xPos - 1;
        if (!Check()) {
            xPos = xPos + 1;
        }
        Draw();
    }

    public void moveRight() {
        rnd += 11;
        Remove();
        xPos = xPos + 1;
        if (!Check()) {
            xPos = xPos - 1;
        }
        Draw();
    }

    public void rotateCounterClockwise() {
        rnd += 5;
        Remove();
        orientation = (orientation + 3) % 4;
        if (!Check()) {
            orientation = (orientation + 1) % 4;
        }
        Draw();
    }
}
